home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / mint / mgr / sparcmgr / demo2.zoo / demo / ex / printf.c < prev    next >
Encoding:
C/C++ Source or Header  |  1987-04-24  |  7.7 KB  |  353 lines

  1. /*
  2.  * Copyright (c) 1980 Regents of the University of California.
  3.  * All rights reserved.  The Berkeley software License Agreement
  4.  * specifies the terms and conditions for redistribution.
  5.  */
  6.  
  7. #ifndef lint
  8. static char *sccsid = "@(#)printf.c    7.4 (Berkeley) 3/9/87; 1.2 (Bellcore)    87/04/24";
  9. /* The pwb version this is based on */
  10. static char *printf_id = "@(#) printf.c:2.2 6/5/79";
  11. #endif not lint
  12.  
  13. #include <varargs.h>
  14.  
  15. /*
  16.  * This version of printf is compatible with the Version 7 C
  17.  * printf. The differences are only minor except that this
  18.  * printf assumes it is to print through putchar. Version 7
  19.  * printf is more general (and is much larger) and includes
  20.  * provisions for floating point.
  21.  */
  22.  
  23. #define MAXOCT    11    /* Maximum octal digits in a long */
  24. #define MAXINT    32767    /* largest normal length positive integer */
  25. #define BIG    1000000000  /* largest power of 10 less than an unsigned long */
  26. #define MAXDIGS    10    /* number of digits in BIG */
  27.  
  28. static int width, sign, fill;
  29.  
  30. char *_p_dconv();
  31.  
  32. /* VARARGS */
  33. ex_printf(va_alist)
  34.     va_dcl
  35. {
  36.     va_list ap;
  37.     register char *fmt;
  38.     char fcode;
  39.     int prec;
  40.     int length,mask1,nbits,n;
  41.     long int mask2, num;
  42.     register char *bptr;
  43.     char *ptr;
  44.     char buf[134];
  45.  
  46.     va_start(ap);
  47.     fmt = va_arg(ap,char *);
  48.     for (;;) {
  49.         /* process format string first */
  50.         while ((fcode = *fmt++)!='%') {
  51.             /* ordinary (non-%) character */
  52.             if (fcode=='\0')
  53.                 return;
  54.             ex_putchar(fcode);
  55.         }
  56.         /* length modifier: -1 for h, 1 for l, 0 for none */
  57.         length = 0;
  58.         /* check for a leading - sign */
  59.         sign = 0;
  60.         if (*fmt == '-') {
  61.             sign++;
  62.             fmt++;
  63.         }
  64.         /* a '0' may follow the - sign */
  65.         /* this is the requested fill character */
  66.         fill = 1;
  67.         if (*fmt == '0') {
  68.             fill--;
  69.             fmt++;
  70.         }
  71.         
  72.         /* Now comes a digit string which may be a '*' */
  73.         if (*fmt == '*') {
  74.             width = va_arg(ap, int);
  75.             if (width < 0) {
  76.                 width = -width;
  77.                 sign = !sign;
  78.             }
  79.             fmt++;
  80.         }
  81.         else {
  82.             width = 0;
  83.             while (*fmt>='0' && *fmt<='9')
  84.                 width = width * 10 + (*fmt++ - '0');
  85.         }
  86.         
  87.         /* maybe a decimal point followed by more digits (or '*') */
  88.         if (*fmt=='.') {
  89.             if (*++fmt == '*') {
  90.                 prec = va_arg(ap, int);
  91.                 fmt++;
  92.             }
  93.             else {
  94.                 prec = 0;
  95.                 while (*fmt>='0' && *fmt<='9')
  96.                     prec = prec * 10 + (*fmt++ - '0');
  97.             }
  98.         }
  99.         else
  100.             prec = -1;
  101.         
  102.         /*
  103.          * At this point, "sign" is nonzero if there was
  104.          * a sign, "fill" is 0 if there was a leading
  105.          * zero and 1 otherwise, "width" and "prec"
  106.          * contain numbers corresponding to the digit
  107.          * strings before and after the decimal point,
  108.          * respectively, and "fmt" addresses the next
  109.          * character after the whole mess. If there was
  110.          * no decimal point, "prec" will be -1.
  111.          */
  112.         switch (*fmt) {
  113.             case 'L':
  114.             case 'l':
  115.                 length = 2;
  116.                 /* no break!! */
  117.             case 'h':
  118.             case 'H':
  119.                 length--;
  120.                 fmt++;
  121.                 break;
  122.         }
  123.         
  124.         /*
  125.          * At exit from the following switch, we will
  126.          * emit the characters starting at "bptr" and
  127.          * ending at "ptr"-1, unless fcode is '\0'.
  128.          */
  129.         switch (fcode = *fmt++) {
  130.             /* process characters and strings first */
  131.             case 'c':
  132.                 buf[0] = va_arg(ap, int);
  133.                 ptr = bptr = &buf[0];
  134.                 if (buf[0] != '\0')
  135.                     ptr++;
  136.                 break;
  137.             case 's':
  138.                 bptr = va_arg(ap,char *);
  139.                 if (bptr==0)
  140.                     bptr = "(null pointer)";
  141.                 if (prec < 0)
  142.                     prec = MAXINT;
  143.                 for (n=0; *bptr++ && n < prec; n++) ;
  144.                 ptr = --bptr;
  145.                 bptr -= n;
  146.                 break;
  147.             case 'O':
  148.                 length = 1;
  149.                 fcode = 'o';
  150.                 /* no break */
  151.             case 'o':
  152.             case 'X':
  153.             case 'x':
  154.                 if (length > 0)
  155.                     num = va_arg(ap,long);
  156.                 else
  157.                     num = (unsigned)va_arg(ap,int);
  158.                 if (fcode=='o') {
  159.                     mask1 = 0x7;
  160.                     mask2 = 0x1fffffffL;
  161.                     nbits = 3;
  162.                 }
  163.                 else {
  164.                     mask1 = 0xf;
  165.                     mask2 = 0x0fffffffL;
  166.                     nbits = 4;
  167.                 }
  168.                 n = (num!=0);
  169.                 bptr = buf + MAXOCT + 3;
  170.                 /* shift and mask for speed */
  171.                 do
  172.                     if (((int) num & mask1) < 10)
  173.                     *--bptr = ((int) num & mask1) + 060;
  174.                     else
  175.                     *--bptr = ((int) num & mask1) + 0127;
  176.                 while (num = (num >> nbits) & mask2);
  177.                 
  178.                 if (fcode=='o') {
  179.                     if (n)
  180.                         *--bptr = '0';
  181.                 }
  182.                 else
  183.                     if (!sign && fill <= 0) {
  184.                         ex_putchar('0');
  185.                         ex_putchar(fcode);
  186.                         width -= 2;
  187.                     }
  188.                     else {
  189.                         *--bptr = fcode;
  190.                         *--bptr = '0';
  191.                     }
  192.                 ptr = buf + MAXOCT + 3;
  193.                 break;
  194.             case 'D':
  195.             case 'U':
  196.             case 'I':
  197.                 length = 1;
  198.                 fcode = fcode + 'a' - 'A';
  199.                 /* no break */
  200.             case 'd':
  201.             case 'i':
  202.             case 'u':
  203.                 if (length > 0)
  204.                     num = va_arg(ap,long);
  205.                 else {
  206.                     n = va_arg(ap,int);
  207.                     if (fcode=='u')
  208.                         num = (unsigned) n;
  209.                     else
  210.                         num = (long) n;
  211.                 }
  212.                 if (n = (fcode != 'u' && num < 0))
  213.                     num = -num;
  214.                 /* now convert to digits */
  215.                 bptr = _p_dconv(num, buf);
  216.                 if (n)
  217.                     *--bptr = '-';
  218.                 if (fill == 0)
  219.                     fill = -1;
  220.                 ptr = buf + MAXDIGS + 1;
  221.                 break;
  222.             default:
  223.                 /* not a control character, 
  224.                  * print it.
  225.                  */
  226.                 ptr = bptr = &fcode;
  227.                 ptr++;
  228.                 break;
  229.             }
  230.             if (fcode != '\0')
  231.                 _p_emit(bptr,ptr);
  232.     }
  233.     va_end(ap);
  234. }
  235.  
  236. /* _p_dconv converts the unsigned long integer "value" to
  237.  * printable decimal and places it in "buffer", right-justified.
  238.  * The value returned is the address of the first non-zero character,
  239.  * or the address of the last character if all are zero.
  240.  * The result is NOT null terminated, and is MAXDIGS characters long,
  241.  * starting at buffer[1] (to allow for insertion of a sign).
  242.  *
  243.  * This program assumes it is running on 2's complement machine
  244.  * with reasonable overflow treatment.
  245.  */
  246. char *
  247. _p_dconv(value, buffer)
  248.     long value;
  249.     char *buffer;
  250. {
  251.     register char *bp;
  252.     register int svalue;
  253.     int n;
  254.     long lval;
  255.     
  256.     bp = buffer;
  257.     
  258.     /* zero is a special case */
  259.     if (value == 0) {
  260.         bp += MAXDIGS;
  261.         *bp = '0';
  262.         return(bp);
  263.     }
  264.     
  265.     /* develop the leading digit of the value in "n" */
  266.     n = 0;
  267.     while (value < 0) {
  268.         value -= BIG;    /* will eventually underflow */
  269.         n++;
  270.     }
  271.     while ((lval = value - BIG) >= 0) {
  272.         value = lval;
  273.         n++;
  274.     }
  275.     
  276.     /* stash it in buffer[1] to allow for a sign */
  277.     bp[1] = n + '0';
  278.     /*
  279.      * Now develop the rest of the digits. Since speed counts here,
  280.      * we do it in two loops. The first gets "value" down until it
  281.      * is no larger than MAXINT. The second one uses integer divides
  282.      * rather than long divides to speed it up.
  283.      */
  284.     bp += MAXDIGS + 1;
  285.     while (value > MAXINT) {
  286.         *--bp = (int)(value % 10) + '0';
  287.         value /= 10;
  288.     }
  289.     
  290.     /* cannot lose precision */
  291.     svalue = value;
  292.     while (svalue > 0) {
  293.         *--bp = (svalue % 10) + '0';
  294.         svalue /= 10;
  295.     }
  296.     
  297.     /* fill in intermediate zeroes if needed */
  298.     if (buffer[1] != '0') {
  299.         while (bp > buffer + 2)
  300.             *--bp = '0';
  301.         --bp;
  302.     }
  303.     return(bp);
  304. }
  305.  
  306. /*
  307.  * This program sends string "s" to putchar. The character after
  308.  * the end of "s" is given by "send". This allows the size of the
  309.  * field to be computed; it is stored in "alen". "width" contains the
  310.  * user specified length. If width<alen, the width will be taken to
  311.  * be alen. "sign" is zero if the string is to be right-justified
  312.  * in the field, nonzero if it is to be left-justified. "fill" is
  313.  * 0 if the string is to be padded with '0', positive if it is to be
  314.  * padded with ' ', and negative if an initial '-' should appear before
  315.  * any padding in right-justification (to avoid printing "-3" as
  316.  * "000-3" where "-0003" was intended).
  317.  */
  318. _p_emit(s, send)
  319.     register char *s;
  320.     char *send;
  321. {
  322.     char cfill;
  323.     register int alen;
  324.     int npad;
  325.     
  326.     alen = send - s;
  327.     if (alen > width)
  328.         width = alen;
  329.     cfill = fill>0? ' ': '0';
  330.     
  331.     /* we may want to print a leading '-' before anything */
  332.     if (*s == '-' && fill < 0) {
  333.         ex_putchar(*s++);
  334.         alen--;
  335.         width--;
  336.     }
  337.     npad = width - alen;
  338.     
  339.     /* emit any leading pad characters */
  340.     if (!sign)
  341.         while (--npad >= 0)
  342.             ex_putchar(cfill);
  343.             
  344.     /* emit the string itself */
  345.     while (--alen >= 0)
  346.         ex_putchar(*s++);
  347.         
  348.     /* emit trailing pad characters */
  349.     if (sign)
  350.         while (--npad >= 0)
  351.             ex_putchar(cfill);
  352. }
  353.